package com.gcloud.mesh.dcs.chain;

import com.gcloud.mesh.dcs.dao.SchedulerJobDao;
import com.gcloud.mesh.dcs.dao.SchedulerStepDao;
import com.gcloud.mesh.dcs.entity.SchedulerStepEntity;
import com.gcloud.mesh.dcs.enums.SchedulerJobStatus;
import com.gcloud.mesh.dcs.enums.SchedulerStepStatus;
import com.gcloud.mesh.dcs.service.MigrateScheduleResultHandler;
import com.gcloud.mesh.supplier.enums.SystemType;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.exception.MyBusinessException;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.SpringContextUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.OrderComparator;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Slf4j
@Component
@Data
public class FilterChain implements IChain {

    Map<String,List<IMigrationStepChain>> chainMap = Maps.newLinkedHashMap();

    @Autowired
    private SchedulerStepDao schedulerStepDao;

    @Autowired
    private SchedulerJobDao schedulerJobDao;

    @Autowired
    private RedisUtil redisUtil;
    
    @Autowired
    private MigrateScheduleResultHandler migrateScheduleResultHandler;


    public int getChainStepCount(SystemType type){
        return chainMap.get(type.getName()).size();
    }

    @Autowired
    public FilterChain(List<IMigrationStepChain> chainList){
        if(chainList==null) return;
        OrderComparator.sort(chainList);
        chainMap = chainList.stream().collect(Collectors.toMap(IMigrationStepChain::chainType, c->{
            List<IMigrationStepChain> baseChains = chainMap.get(c.chainType());
            if(baseChains!=null){
                baseChains.add(c);
                return baseChains;
            }
            ArrayList<IMigrationStepChain> list = Lists.newArrayList(c);
            chainMap.put(c.chainType(),list);
            return list;
        },(k1,k2)->k2));
    }


    @Override
    public void doExec(String schedulerJobId, String attach, FilterChain filterChain, IMigrationStepChain stepChain) {
        List<IMigrationStepChain> baseChains = chainMap.get(stepChain.chainType());
        if(baseChains==null) return;
        AtomicInteger position = new AtomicInteger();
        Optional<IMigrationStepChain> currentChain = baseChains.stream().peek(c->position.incrementAndGet()).filter(c -> c.getClass().getName().equals(stepChain.getClass().getName())).findFirst();
        if(currentChain.isPresent()){
            int pos = position.get();
            if(pos>=baseChains.size()) {
                //最后一步
                if(stepChain.isSyncChain()){
                    this.finishPreStepStatus(schedulerJobId,currentChain.get().getExecResult());
                    schedulerJobDao.updateJobStatusById(schedulerJobId,SchedulerJobStatus.SUCCESS);
                    //zhangdp增加修改数据库的相关记录
                    migrateScheduleResultHandler.handleMigrate(schedulerJobId);
                }
                return;
            }
            if(stepChain.isSyncChain()){
                this.finishPreStepStatus(schedulerJobId,currentChain.get().getExecResult());
                IMigrationStepChain nextStep = baseChains.get(pos);
                nextStep.doExec(schedulerJobId,attach,filterChain,nextStep);
            }else{
                //记录attach到redis，在定时任务中使用
                redisUtil.set(MigrationConstant.ATTACH_KEY_EXEC+schedulerJobId,attach,24*60*60);
            }
        }
    }

    @Override
    public int getOrder() {
        return 0;
    }

    public void finishPreStepStatus(String schedulerJobId,String result){
        //更新最后一条为完成
        List<Object> params = Lists.newArrayList();
        params.add(schedulerJobId);
        String sql = "select id from dcs_scheduler_steps t where t.scheduler_job_id = ? and t.end_time is null order by id desc limit 1";
        List<SchedulerStepEntity> ssList = schedulerStepDao.findBySql(sql, params);
        if(ssList!=null && !ssList.isEmpty()){
            schedulerStepDao.updateStepStatusById(ssList.get(0).getId(), SchedulerStepStatus.SUCCESS,result);
        }
    }

    public void start(SystemType systemType,String schedulerJobId,String attach){
        List<IMigrationStepChain> listStep = chainMap.get(systemType.getName());
        if(listStep==null || listStep.isEmpty()) throw new MyBusinessException("找不到"+systemType.getName()+"迁移实现类");
        IMigrationStepChain firstStepChain = listStep.get(0);
        firstStepChain.doExec(schedulerJobId,attach,this,firstStepChain);
    }

    public IMigrationStepChain getNextStep(IMigrationStepChain currentStep){
        List<IMigrationStepChain> baseChains = chainMap.get(currentStep.chainType());
        if(baseChains==null) return currentStep;
        AtomicInteger position = new AtomicInteger();
        Optional<IMigrationStepChain> currentChain = baseChains.stream().peek(c->position.incrementAndGet()).filter(c -> c.getClass().getName().equals(currentStep.getClass().getName())).findFirst();
        if(currentChain.isPresent()){
            int pos = position.get();
            if(pos>=baseChains.size()) {
                return currentStep;
            }
            return baseChains.get(pos);
        }
        return currentStep;
    }

    public void restart(String schedulerJobStepId){
        SchedulerStepEntity schedulerStepEntity = schedulerStepDao.getById(schedulerJobStepId);
        if(schedulerStepEntity==null) throw new MyBusinessException("没找到需要重新执行的步骤");
        if(schedulerStepEntity.getStatus()!=2) throw new MyBusinessException("只允许失败步骤执行此操作。");
        String processClass = schedulerStepEntity.getProcessClass();
        String attach = schedulerStepEntity.getAttach();
        String schedulerJobId = schedulerStepEntity.getSchedulerJobId();
        IMigrationStepChain bean = null;
        try {
            Class<IMigrationStepChain> stepChainClass = (Class<IMigrationStepChain>) Class.forName(processClass);
            bean = SpringContextUtils.getBean(stepChainClass);
        } catch (ClassNotFoundException e) {
            throw new MyBusinessException("找不到该步骤的实现类");
        }
        //查看是否执行成功
        if(bean.checkStatus(schedulerJobStepId)){
            schedulerStepDao.updateStepStatusById(schedulerJobStepId,SchedulerStepStatus.SUCCESS,"");
            //执行下一步
            IMigrationStepChain nextStep = getNextStep(bean);
            if(nextStep.getOrder()==bean.getOrder()) {
                schedulerJobDao.updateJobStatusById(schedulerJobId,SchedulerJobStatus.SUCCESS);
                migrateScheduleResultHandler.handleMigrate(schedulerJobId);
                return;
            }
            schedulerJobDao.updateJobStatusById(schedulerJobId,SchedulerJobStatus.PROGRESS);
            Object o = redisUtil.get(MigrationConstant.ATTACH_KEY_EXEC + schedulerJobId);
            if(o!=null) attach = o.toString();
            nextStep.doExec(schedulerJobId,attach,this,nextStep);
            return;
        }
        schedulerJobDao.updateJobStatusById(schedulerJobId,SchedulerJobStatus.PROGRESS);
        schedulerStepDao.deleteById(schedulerStepEntity.getId());
        bean.doExec(schedulerJobId,attach,this,bean);
    }

}
